package net.homeip.mmhg.web;

import java.util.HashMap;
import java.util.Map;

import net.homeip.mmhg.domain.Task;
import net.homeip.mmhg.events.EventPublisher;
import net.homeip.mmhg.events.PositionEvent;
import net.homeip.mmhg.events.TaskEvent;
import net.homeip.mmhg.events.Event.EventType;
import net.homeip.mmhg.game.AttemptResultInfo;
import net.homeip.mmhg.game.GameContext;
import net.homeip.mmhg.game.GameJob;
import net.homeip.mmhg.game.Position;
import net.homeip.mmhg.game.AttemptResultInfo.AttemptResult;
import net.homeip.mmhg.util.DateUtil;

import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SimpleTrigger;
import org.quartz.Trigger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.annotation.Secured;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

/**
 * Starts and stops the game. 
 *
 * @author ilya gerasimov
 */
@Controller
public class GameController {
	
	private static String GAME_START_JOB_NAME = "gameStart";
	private static String GAME_STOP_JOB_NAME = "gameStop";
	private static String GAME_GROUP = "game";
	private static String HOME_PAGE_REDIRECT = "redirect:/home.htm";
	private static String MESSAGE_ATTR = "message";
	
	private GameContext context;
	private Scheduler scheduler;
	private EventPublisher publisher;
	
	@Autowired
	public void setGameContext(GameContext context) {
		this.context = context;
	}
	
	@Autowired
	public void setEventPublisher(EventPublisher publisher) {
		this.publisher = publisher;
	}
	
	@Autowired
	public void setScheduler(Scheduler scheduler) {
		this.scheduler = scheduler;
	}
	
	@RequestMapping("/start_game.htm")
	@Secured("ROLE_ADMINISTRATOR")
	public String startGame() throws SchedulerException {
		scheduler.deleteJob(GAME_START_JOB_NAME, GAME_GROUP);
		context.start();
		return HOME_PAGE_REDIRECT;
	}
	
	@RequestMapping("/ch_enable.htm")
	@Secured("ROLE_ADMINISTRATOR")
	public String changeEnable(@RequestParam("id") Integer taskID) {
		Task task = context.getTaskMap().get(taskID);
		task.setEnabled(!task.isEnabled());
		task.setBlockingStart(new DateTime());
		publisher.publish(new TaskEvent(task.isEnabled() ? EventType.TASK_UNBLOCKED
														 : EventType.TASK_BLOCKED, task));
		return "forward:/task_dlg.htm";
	}
	
	@RequestMapping("/start_at_time.htm")
	@Secured("ROLE_ADMINISTRATOR")
	public String setStart(@RequestParam(value = "start_time", required = false) String stringTime) throws SchedulerException {
		context.setStart(schedule(new DateTime(), stringTime, GAME_START_JOB_NAME));
		return HOME_PAGE_REDIRECT;
	}

	@RequestMapping("/stop_game.htm")
	@Secured("ROLE_ADMINISTRATOR")
	public String stopGame() throws SchedulerException {
		scheduler.deleteJob(GAME_STOP_JOB_NAME, GAME_GROUP);
		context.stop();
		return HOME_PAGE_REDIRECT;
	}
	
	@RequestMapping("/stop_at_time.htm")
	@Secured("ROLE_ADMINISTRATOR")
	public String setStop(@RequestParam(value = "stop_time", required = false) String stringTime) throws SchedulerException {
		context.setEnd(schedule(new DateTime(), stringTime, GAME_STOP_JOB_NAME));
		return HOME_PAGE_REDIRECT;
	}
	
	@RequestMapping("/new_game.htm")
	@Secured("ROLE_ADMINISTRATOR")
	public String newGame() {
		context.initialize();
		return HOME_PAGE_REDIRECT;
	}
	
	private DateTime schedule(DateTime date, String stringTime, String jobName) throws SchedulerException {
		if ( (stringTime != null) && (!stringTime.isEmpty())){
			DateTime dt = DateTimeFormat.forPattern("HH:mm").parseDateTime(stringTime);
			DateTime time = DateUtil.setTime(date, dt);
			scheduler.deleteJob(jobName, GAME_GROUP);
			JobDetail jobDetail = new JobDetail(jobName, GAME_GROUP, GameJob.class);
			Trigger trigger = new SimpleTrigger(jobName, GAME_GROUP, time.toDate());
			scheduler.scheduleJob(jobDetail, trigger);
			return time;
		} else {
			scheduler.deleteJob(GAME_START_JOB_NAME, GAME_GROUP);
			return null;
		}
	}
	
	@RequestMapping(value = "/task_dlg.htm")
	@Secured("ROLE_ADMINISTRATOR")
	public Map<String, Object> getTask(@RequestParam("id") Integer taskID) {
		Map<String, Object> map = new HashMap<String, Object>(1);
		map.put("task", context.getTaskMap().get(taskID));
		return map;
	}
	
	@RequestMapping(value = "/export.htm")
	@Secured("ROLE_ADMINISTRATOR")
	public ModelAndView export() {
		return new ModelAndView("export", "gameContext", context);
	}
	
	@RequestMapping("/block_team.htm")
	@Secured("ROLE_ADMINISTRATOR")
	public String blockTeam(@RequestParam("id") Integer teamID) {
		Position position = context.getTeamPosition(teamID);
		if (!position.getTeam().isBlocked()) {
			context.blockTeam(position);
		} else {
			context.unblockTeam(position);
		}
		return "forward:/team_dlg.htm";
	}
	
	@RequestMapping(value = "/team_dlg.htm")
	@Secured("ROLE_ADMINISTRATOR")
	public Map<String, Object> getTeam(@RequestParam("id") Integer teamID) {
		Map<String, Object> map = new HashMap<String, Object>(1);
		map.put("position", context.getTeamPosition(teamID));
		return map;
	}
	
	@RequestMapping(value = "/ext_try.htm")
	@Secured("ROLE_ADMINISTRATOR")
	public ModelAndView extTryGuess(@RequestParam("guess") String guess,
									@RequestParam("id") Integer teamID,
									@RequestParam("taskID") Integer taskID) {
		Position position = context.getTeamPosition(teamID);
		ModelAndView mav = new ModelAndView("forward:/team_dlg.htm");
		if (taskID.equals(position.getObtainedTask().getTask().getId())) {
			if ( (guess != null) && (!guess.isEmpty())){
				AttemptResultInfo resultInfo = context.tryGuess(teamID, guess);
				if (resultInfo.getResult() == AttemptResult.FINISHED) {
					mav.addObject(MESSAGE_ATTR, "messages.task.finished");
				} else if (resultInfo.getResult() == AttemptResult.MISSED) {
					mav.addObject(MESSAGE_ATTR, "messages.task.missed");
				} else if (resultInfo.getResult() == AttemptResult.PARTIALLY_GUESSED) {
					mav.addObject(MESSAGE_ATTR, "messages.task.partially_guessed");
					mav.addObject("infoString", "resultInfo.getWrongAnswers()");
				} else if(resultInfo.getResult() == AttemptResult.GUESSED) {
					mav.addObject(MESSAGE_ATTR, "messages.task.guessed");
				} else {
					mav.addObject(MESSAGE_ATTR, "messages.task.rejected");
				}
			}
		}
		return mav;
	}
	
	@RequestMapping(value = "/ext_reject.htm")
	@Secured("ROLE_ADMINISTRATOR")
	public ModelAndView extReject(@RequestParam("id") Integer teamID,
								  @RequestParam("taskID") Integer taskID) {
		ModelAndView mav = new ModelAndView("forward:/team_dlg.htm");
		Position position = context.getTeamPosition(teamID);
		if (taskID.equals(position.getObtainedTask().getTask().getId())) {
			context.rejectTask(position.getTeam());
			publisher.publish(new PositionEvent(EventType.FORCE_REJECT, position));
			mav.addObject(MESSAGE_ATTR, "messages.task.rejected_by_himself");
		}
		return mav;
	}
}
